﻿
using DataWorks_Tools.MappModals.CalSaveModals;
using MathNet.Numerics.LinearAlgebra;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace DataWorks_Tools.HalfHourCalSave.Common.Basic
{
    public struct PeakValleyFromtoStru
    {
        public int upordown;
        public int fromindex;
        public int toindex;
        public double spdfrom;
        public double spdto;
        public PeakValleyFromtoStru(int upordown, int fromindex, int toindex, double spdfrom, double spdto)
        {
            this.upordown = upordown;
            this.fromindex = fromindex;
            this.toindex = toindex;
            this.spdfrom = spdfrom;
            this.spdto = spdto;
        }
    }

    public static class SpdFromtoMethods
    {
        /// <summary>
        /// 普通法获取峰谷值的序号 
        /// </summary>
        /// <param name="lst"></param>
        /// <returns></returns>
        public static List<int> FindpeaksIndex(this List<double> lst)
        {
            List<int> result = new List<int>() { 0 };
            int i = 1;
            int count = lst.Count;
            //如果数组的元素的数量大于等于3的时候才能执行下面的比较运算
            while (i < count - 1)
            {
                //前面条件是峰取后面，后面条件是谷取前面，峰取前面或者后面区别不大，因为峰值总会有差，不会完全相等，但谷值会有0相等的情况，所以有必要考虑
                if ((lst[i] >= lst[i - 1] && lst[i + 1] < lst[i]) || (lst[i] < lst[i - 1] && lst[i + 1] >= lst[i]))
                {
                    result.Add(i);
                }
                i++;
            }
            if (result[result.Count - 1] != lst.Count - 1)
            {
                result.Add(lst.Count - 1);
            }
            return result;
        }

        /// <summary>
        ///获取元数据集两两元素的差值并获得PeakValleyFromto结构体数据集（用于峰谷值的差值计算）
        /// </summary>
        /// <param name="lst">峰谷值元数据集</param>
        /// <param name="index">峰谷值的index</param>
        /// <returns>返回差值集</returns>
        public static List<PeakValleyFromtoStru> GetPeakValleyFromtoList(this List<double> lst, List<int> index)
        {
            List<PeakValleyFromtoStru> result = new List<PeakValleyFromtoStru>();
            for (int i = 0; i < lst.Count - 1; i++)
            {
                double difference = lst[i + 1] - lst[i];
                if (difference > 1)
                {
                    result.Add(new PeakValleyFromtoStru
                    {
                        upordown = 0,
                        toindex = index[i + 1],
                        fromindex = index[i],
                        spdfrom = lst[i],
                        spdto = lst[i + 1]
                    });
                }
                else if (difference < -1)
                {
                    result.Add(new PeakValleyFromtoStru
                    {
                        upordown = 1,
                        toindex = index[i + 1],
                        fromindex = index[i],
                        spdfrom = lst[i],
                        spdto = lst[i + 1]
                    });
                }
            }
            return result;
        }

        /// <summary>
        /// 利用递归来合并spd切片
        /// </summary>
        /// <param name="lst"></param>
        /// <param name="index"></param>
        /// <returns></returns>
        public static List<PeakValleyFromtoStru> CombinePeakValleyFromtoStru(this List<PeakValleyFromtoStru> lst, int index)
        {
            // 结束递归条件  
            if (index >= lst.Count - 1) return lst;

            // 如果当前元素与下一个元素的 upordown 一致，且 toindex 差小于16  
            if (lst[index].upordown == lst[index + 1].upordown &&
                (lst[index + 1].fromindex - lst[index].toindex) < 16)
            {
                // 新合并的元素  
                var mergedElement = new PeakValleyFromtoStru(
                    lst[index].upordown,
                    lst[index].fromindex,
                    lst[index + 1].toindex,
                    lst[index].spdfrom,
                    lst[index + 1].spdto
                );
                lst.RemoveAt(index);// 移除 index 和 index + 1 的元素, 并插入合并的元素  
                lst.RemoveAt(index); // 第二个元素的索引现在已经改变了  

                lst.Insert(index, mergedElement);
                return CombinePeakValleyFromtoStru(lst, index); // 递归继续处理相同位置  
            }
            else
            {
                return CombinePeakValleyFromtoStru(lst, index + 1); // 移动到下一个元素  
            }
        }
        /// <summary>
        /// 根据第一个0的输入index获取这段0数据集的最后一个0的index（修正谷值取前面的问题）
        /// </summary>
        /// <param name="lst"></param>
        /// <param name="index"></param>
        /// <returns></returns>
        public static int GetLastZeroIndex(this List<double> lst, int index)
        {
            if (lst.Count > index)
            {
                int start = index;
                while (lst[start] == 0)
                {
                    start++;
                }
                return start;
            }
            else
            {
                return index;
            }
        }

        /// <summary>
        /// 修改PeakValleyFromtoStru的结构体里符合条件元素的fromindex的值为一段0数据的最后一个0的index
        /// </summary>
        /// <param name="lst"></param>
        /// <param name="zerospd"></param>
        /// <returns></returns>
        public static void EditStruforLastZero(this List<PeakValleyFromtoStru> lst, List<double> zerospd)
        {
            for (int i = 0; i < lst.Count; i++)
            {
                if (lst[i].spdfrom == 0)
                {
                    var item = lst[i];
                    item.fromindex = zerospd.GetLastZeroIndex(item.fromindex);
                    lst[i] = item; // 更新列表中的元素  
                }
            }
        }


        public static List<int> FindpeaksIndexSpecial(this List<double> lst)
        {
            List<int> result = new List<int>() { 0 };
            int count = lst.Count;
            int j = 1;
            while (j < count - 1)
            {
                //Console.WriteLine($"j:{j}");
                if ((lst[j] >= lst[j - 1] && lst[j + 1] < lst[j]))
                {
                    int k = j + 1;
                    //然后循环去计算后面的是否比前面的小，小的一直循环下去，直到出现一个大的，说明找到底了，这个时候去计算峰谷之间的大小
                    //lst[k+1]不能超过原始数据的个数
                    while (k + 1 < count)
                    {
                        //Console.WriteLine($"k:{k}");
                        if (lst[k] >= lst[k + 1])
                        {
                            k++;
                            if (k == count - 1)
                            {
                                j = k; break;
                            }
                        }
                        else
                        {
                            if (lst[j] - lst[k] > 5)
                            {
                                result.Add(j);
                                result.Add(k);
                                j = k + 1;
                                break;
                            }
                            else
                            {
                                j = k + 1;
                                break;
                            }
                        }
                    }
                }
                else if (lst[j] <= lst[j - 1] && lst[j + 1] > lst[j])
                {
                    int k = j + 1;
                    //然后循环去计算后面的是否比前面的小，小的一直循环下去，直到出现一个大的，说明找到底了，这个时候去计算峰谷之间的大小
                    //lst[k+1]不能超过原始数据的个数
                    while (k + 1 < count)
                    {
                        //Console.WriteLine($"k:{k}");
                        if (lst[k] <= lst[k + 1])
                        {
                            k++;
                            if (k == count - 1)
                            {
                                j = k; break;
                            }
                        }
                        else
                        {
                            if (lst[k] - lst[j] > 5)
                            {
                                result.Add(j);
                                result.Add(k);
                                j = k + 1;
                                break;
                            }
                            else
                            {
                                j = k + 1;
                                break;
                            }
                        }
                    }
                }
                else
                {
                    j++;
                }
            }
            result.Add(count - 1);
            return result;

        }


        /// <summary>
        /// 差分法获取峰谷值的序号
        /// </summary>
        /// <param name="lst">数据源</param>
        /// <returns>List<double></returns>
        public static List<int> FindpeaksIndexDiff(this List<double> lst)
        {
            List<int> pvindex = new List<int>();

            if (lst.Count > 0)
            {
                List<int> diff = new List<int>();
                List<int> diff2 = new List<int>();
                List<int> zeroindex = new List<int>();

                //差分计算后一个点-前一个点
                for (int i = 0; i < lst.Count - 1; i++)
                {
                    if (lst[i + 1] - lst[i] > 0)
                    {
                        diff.Add(1);
                    }
                    else if (lst[i + 1] - lst[i] == 0)
                    {

                        diff.Add(0);
                    }
                    else
                    {
                        diff.Add(-1);
                    }
                }
                //如果是0点再看前一个点是否不为0来判断,用2个list来保存需要改为1和-1的index
                List<int> positivelist = new List<int>();
                List<int> nagitivelist = new List<int>();
                for (int i = 1; i < diff.Count; i++)
                {
                    if (diff[i] == 0 && diff[i - 1] < 0)
                    {
                        nagitivelist.Add(i);
                    }
                    else if (diff[i] == 0 && diff[i - 1] > 0)
                    {
                        positivelist.Add(i);
                    }
                }
                //改1和-1
                for (int i = 0; i < positivelist.Count; i++)
                {
                    diff[positivelist[i]] = 1;
                }
                for (int i = 0; i < nagitivelist.Count; i++)
                {
                    diff[nagitivelist[i]] = -1;
                }
                //再进行差分，最后只有-2,0,2。-2为峰，2为谷
                for (int i = 0; i < diff.Count - 1; i++)
                {
                    diff2.Add(diff[i + 1] - diff[i]);
                }
                for (int i = 0; i < diff2.Count; i++)
                {
                    if (diff2[i] == -2 || diff2[i] == 2)
                    {
                        pvindex.Add(i + 1);
                    }
                }
            }
            return pvindex;
        }
        /// <summary>
        /// 根据原始信号及需要的选出的序号来获取需要的数据
        /// </summary>
        /// <param name="lst"></param>
        /// <param name="index"></param>
        /// <returns></returns>
        public static List<double> GetDataValues(this List<double> lst, List<int> index)
        {
            List<double> data = new();
            if (lst.Count > 0)
            {
                for (int i = 0; i < index.Count; i++)
                {
                    data.Add(lst[index[i]]);
                }
            }
            return data;
        }
        /// <summary>
        /// 把小于0.1的速度都置为0
        /// </summary>
        /// <param name="lst"></param>
        /// <returns></returns>
        public static List<double> DoSpdZero(this List<double> lst)
        {
            List<double> result = new List<double>();
            for (int i = 0; i < lst.Count; i++)
            {
                if (Math.Abs(lst[i]) <= 1)
                {
                    result.Add(0);
                }
                else
                {
                    result.Add(lst[i]);
                }
            }
            return result;
        }

        public static List<double> GetDataValues(this List<double> lst, int startidx, int endidx)
        {
            List<double> data = new();
            if (lst.Count > endidx)
            {
                for (int i = startidx; i <= endidx; i++)
                {
                    data.Add(lst[i]);
                }
            }
            return data;
        }
        public static List<int> GetIndexValues(this List<int> lst, List<int> index)
        {
            List<int> data = new();
            if (lst.Count > 0)
            {
                for (int i = 0; i < index.Count; i++)
                {
                    data.Add(lst[index[i]]);
                }
            }
            return data;
        }
        /// <summary>
        ///获取小载荷数据的序号(需要先找到peakvalue后再做这个）
        /// </summary>
        /// <param name="lst"></param>
        /// <returns></returns>
        public static List<int> FindSmallLoadIndex(this List<double> lst)
        {
            List<int> numlist = new List<int>();
            if (lst.Count > 0)
            {
                var max = lst.Max();
                var min = lst.Min();
                for (int i = 0; i < lst.Count - 1; i++)
                {
                    if (Math.Abs(lst[i] - lst[i + 1]) < 5)
                    {
                        if (lst[i + 1] != max && lst[i + 1] != min)
                        {
                            numlist.Add(i + 1);
                        }
                    }
                }
                ////倒序删除List数据
                //for (int i = numlist.Count - 1; i >= 0; i--)
                //{
                //    lst.RemoveAt(numlist[i]);
                //}
            }
            return numlist;
        }

        /// <summary>
        /// 根据速度value的值来确定它属于哪个bin,bin间隔为5，这里要注意速度可能为负，就按0处理
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        public static int GetSpdBin(this double value)
        {
            if (value <= 0)
            {
                return 1;
            }
            else if (value > 200)
            {
                return 40;
            }
            else
            {
                return (int)Math.Ceiling(value / 5);
            }
        }

        /// <summary>
        /// 根据起始index和终止index来获得这期间内的最大值
        /// </summary>
        /// <param name="data"></param>
        /// <param name="start"></param>
        /// <param name="end"></param>
        /// <returns></returns>
        public static double GetMaxValue(this List<double> data, int start, int end)
        {
            List<double> result = new List<double>();
            if (data.Count > end)
            {
                for (int i = start; i <= end; i++)
                {
                    result.Add(data[i]);
                }
            }
            return result.Max();
        }
        /// <summary>
        /// 根据起始index和终止index来获得这期间内的最小值
        /// </summary>
        /// <param name="data"></param>
        /// <param name="start"></param>
        /// <param name="end"></param>
        /// <returns></returns>
        public static double GetMinValue(this List<double> data, int start, int end)
        {
            List<double> result = new List<double>();
            if (data.Count > end)
            {
                for (int i = start; i <= end; i++)
                {
                    result.Add(data[i]);
                }
            }
            return result.Min();
        }
        /// <summary>
        /// 获得加速制动的各类工况的种类
        /// </summary>
        /// <param name="accordec"></param>
        /// <param name="throttle"></param>
        /// <param name="brake"></param>
        /// <returns></returns>
        public static byte GetConditionType(bool accordec, double throttle, double brake)
        {
            //加速
            if (accordec)
            {
                if (brake > 0)
                {
                    if (throttle > 0)
                    {
                        return 3;
                    }
                    else
                    {
                        return 4;
                    }
                }
                else
                {
                    if (throttle > 0)
                    {
                        return 1;
                    }
                    else
                    {
                        return 2;
                    }
                }
            }
            else
            {
                if (brake > 0)
                {
                    if (throttle > 0)
                    {
                        return 6;
                    }
                    else
                    {
                        return 5;
                    }
                }
                else
                {
                    if (throttle > 0)
                    {
                        return 7;
                    }
                    else
                    {
                        return 8;
                    }
                }
            }
        }
        /// <summary>
        /// 获得加速制动的加速度等级
        /// </summary>
        /// <param name="acc"></param>
        /// <returns></returns>
        public static byte GetAccLevel(this double acc)
        {
            //加速
            if (acc < 0)
            {
                if (Math.Abs(acc) < 0.14)
                {
                    return 1;
                }
                else if (Math.Abs(acc) < 0.28)
                {
                    return 2;
                }
                else
                {
                    return 3;
                }
            }
            else
            {
                if (Math.Abs(acc) < 0.14)
                {
                    return 4;
                }
                else if (Math.Abs(acc) < 0.28)
                {
                    return 5;
                }
                else
                {
                    return 6;
                }
            }
        }

        /// <summary>
        /// 数据降采样
        /// </summary>
        /// <param name="lst"></param>
        /// <param name="downsample"></param>
        /// <returns></returns>
        public static List<double> DownSample(this List<double> lst, int downsample)
        {
            var data = lst.Where((value, index) => index % downsample == 0).ToList();
            return data;
        }


    }
}
